package com.tender;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipInputStream;

public class EasyTestEasy4API {

    /**
     * 生成Activiti的相关的表结构
     */
    @Test
    public void test01() {
        // 使用 classpath 下的 activiti.cfg.xml 中的配置来创建 ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(engine);
    }

    /**
     * 自定义的方式来加载配置文件
     */
    @Test
    public void test02() {
        // 首先创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration =
                ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        // 通过ProcessEngineConfiguration对象来创建 ProcessEngine对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println(processEngine);
    }

    /**
     * 实现文件的单个部署
     */
    @Test
    public void test03() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        // 执行之前，mvn clean install 下，否则会找不到文件
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/tender_evection.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/tender_evection.png") // 添加png资源
                .name("出差申请流程")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称：" + deploy.getName());
    }

    /**
     * 通过一个zip文件来部署操作
     */
    @Test
    public void test04() {
        // 定义zip文件的输入流
        // 如果 inputStream 为null ，则需要 mvn install 下。
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/tender_evection.zip");
        // 对 inputStream 做装饰
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("出差申请流程")
                .deploy();
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称：" + deploy.getName());
    }

    /**
     * 启动一个流程实例
     */
    @Test
    public void test05() {
        // 1.创建ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService对象
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.根据流程定义的 key 启动流程
        // 流程定义的 key 可以在 act_re_procdef 中找到，可以查看 KEY_ 字段。
        String key = "tender_evection";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);

        // 4.输出相关的流程实例信息
        System.out.println("流程定义的ID：" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例的ID：" + processInstance.getId());
        System.out.println("当前活动的ID：" + processInstance.getActivityId());

        /**
         * 流程定义的ID：tender_evection:1:4
         * 流程实例的ID：2501
         * 当前活动的ID：null
         */
    }

    /**
     * 任务查询
     */
    @Test
    public void test06() {
        // 人事审批人员是 hr_tender
        String assignee = "hr_tender";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 任务查询 需要获取一个 TaskService 对象
        TaskService taskService = engine.getTaskService();
        // 根据流程的key和任务负责人 查询任务，查询打印出来的关键 sql 如下
        // select distinct RES.* from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_
        // WHERE RES.ASSIGNEE_ = ? and D.KEY_ = ? order by RES.ID_ asc LIMIT ? OFFSET ?
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("tender_evection")
                .taskAssignee(assignee)
                .list();
        // 输出当前用户具有的任务
        System.out.println("------------ 结果遍历--------------");
        for (Task task : tasks) {
            System.out.println("流程实例id：" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人：" + task.getAssignee());
            System.out.println("任务名称：" + task.getName());
        }

        /**
         * 流程实例id：2501
         * 任务id:2505
         * 任务负责人：hr_tender
         * 任务名称：人事审批
         */
    }

    /**
     * 流程任务的处理
     */
    @Test
    public void test07() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("tender_evection")
                .processInstanceId("12501")
                // .processInstanceBusinessKey("1001")  // 和 业务key 关联查询
                .taskAssignee("hr_tender")
                .singleResult();
        // 完成任务
        if (null != task) {
            // 任务存在
            System.out.println("任务名称: " + task.getName() + " 存在");
            taskService.complete(task.getId());
        } else {
            System.out.println("Assignee: " + "hr_tender" + " 对应的 task 不存在!");
        }
    }


    /**
     * 查询流程的定义
     */
    @Test
    public void test08() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        // 获取一个 ProcessDefinitionQuery 对象 用来查询操作
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list =
                processDefinitionQuery.processDefinitionKey("tender_evection")
                        .orderByProcessDefinitionVersion() // 安装版本排序
                        .desc() // 倒序
                        .list();
        // 输出流程定义的信息
        for (ProcessDefinition processDefinition : list) {
            System.out.println("流程定义的ID：" + processDefinition.getId());
            System.out.println("流程定义的name：" + processDefinition.getName());
            System.out.println("流程定义的key:" + processDefinition.getKey());
            System.out.println("流程定义的version:" + processDefinition.getVersion());
            System.out.println("流程部署的id:" + processDefinition.getDeploymentId());
        }
    }

    /**
     * 删除流程
     */
    @Test
    public void test09() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        // 删除流程定义，如果该流程定义已经有了流程实例启动则删除时报错
        repositoryService.deleteDeployment("1");
        // 设置为TRUE 级联删除流程定义，及时流程有实例启动，也可以删除，设置为false 非级联删除操作
        //repositoryService.deleteDeployment("1",true);
    }

    /**
     * 读取数据库中的资源文件
     */
    @Test
    public void test10() throws Exception {
        // 1.得到ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService对象
        RepositoryService repositoryService = engine.getRepositoryService();
        // 3.得到查询器
        ProcessDefinition definition =
                repositoryService.createProcessDefinitionQuery()
                        .processDefinitionKey("tender_evection")
                        .singleResult();
        // 4.获取流程部署的id
        String deploymentId = definition.getDeploymentId();
        System.out.println("流程部署的id = " + deploymentId);
        // 5.通过repositoryService对象的相关方法 来获取图片信息和bpmn信息
        // png图片
        InputStream pngInput = repositoryService
                .getResourceAsStream(deploymentId,
                        definition.getDiagramResourceName());
        // bpmn 文件的流
        InputStream bpmnInput = repositoryService
                .getResourceAsStream(deploymentId,
                        definition.getResourceName());
        // 6.文件的保存
        File filePng = new File("d:/evection.png");
        File fileBpmn = new File("d:/evection.bpmn");
        OutputStream pngOut = new FileOutputStream(filePng);
        OutputStream bpmnOut = new FileOutputStream(fileBpmn);
        IOUtils.copy(pngInput, pngOut);
        IOUtils.copy(bpmnInput, bpmnOut);
        pngInput.close();
        pngOut.close();
        bpmnInput.close();
        bpmnOut.close();
    }

    /**
     * 流程历史信息查看
     */
    @Test
    public void test11() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 查看历史信息我们需要通过 HistoryService来实现
        HistoryService historyService = engine.getHistoryService();
        // 获取 actinst 表的查询对象
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        // 查看 act_re_procdef 表中的 ID_ 字段
        instanceQuery.processDefinitionId("tender_evection:1:4");
        instanceQuery.orderByHistoricActivityInstanceStartTime().desc();
        List<HistoricActivityInstance> list = instanceQuery.list();
        // 输出查询的结果
        for (HistoricActivityInstance hi : list) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getActivityType());
            System.out.println(hi.getAssignee());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
            System.out.println("-----------------------");
        }

        /**
         * sid-81B0B371-1AA2-450F-A733-DFB059C9F493
         * null
         * endEvent
         * null
         * tender_evection:1:4
         * 2501
         * -----------------------
         * sid-07B509D4-7BCA-438A-AEAB-330749397587
         * 经理审批
         * userTask
         * manager_tender
         * tender_evection:1:4
         * 2501
         * -----------------------
         * sid-C779C913-6A02-4E3A-ABBA-2B5C1DEBFD99
         * 人事审批
         * userTask
         * hr_tender
         * tender_evection:1:4
         * 2501
         * -----------------------
         * startEvent1
         * null
         * startEvent
         * null
         * tender_evection:1:4
         * 2501
         * -----------------------
         */
    }


}
